///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef __BUOLA_PYTHON_AUTO_DEFINES_H__
#define __BUOLA_PYTHON_AUTO_DEFINES_H__

namespace buola {

#define PYTHON_GET(n)      PythonGetWrapper_##n

#define PYTHON_SET(n)      PythonSetWrapper_##n

#define PYTHON_METHOD(n)   PythonMethodWrapper_##n
#define PYTHON_METHOD_TYPE(n)   PythonMethodType_##n

#define PYTHON_FUNCTION(n) PythonFunctionWrapper_##n
#define PYTHON_FUNCTION_TYPE(n) PythonFunctionType_##n

#define ADD_PYTHON_METHOD(str,n,doc)    mType->AddMethod(str,               \
            PYTHON_METHOD(n),PYTHON_METHOD_TYPE(n),doc)

#define ADD_PYTHON_GET(str,n,doc)   mType->AddGetSet(str,                   \
            PYTHON_GET(n),nullptr,doc)

#define ADD_PYTHON_GETSET(str,n,doc)    mType->AddGetSet(str,               \
            PYTHON_GET(n),PYTHON_SET(n),doc)

#define ADD_PYTHON_FUNCTION(mod,str,n,doc)  mod.AddMethod(str,             \
            PYTHON_FUNCTION(n),PYTHON_FUNCTION_TYPE(n),doc)

#define DEFINE_PYTHON_METHOD(n)                                             \
static const int PYTHON_METHOD_TYPE(n)=METH_VARARGS;                        \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,PyObject *pArgs)     \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n(pArgs)).IncRef();         \
    }                                                                       \
    catch(std::exception &pX)                                               \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject n(const python::YObject&)

#define DEFINE_PYTHON_FUNCTION(n)                                           \
static const int PYTHON_FUNCTION_TYPE(n)=METH_VARARGS;                      \
static python::YObject n(const python::YObject&);                                           \
static PyObject *PYTHON_FUNCTION(n)(PyObject*,PyObject *pArgs)         \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (n(pArgs)).IncRef();                                         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}

#define DEFINE_PYTHON_FUNCTION_NOARGS(n)                                    \
static const int PYTHON_FUNCTION_TYPE(n)=METH_NOARGS;                       \
static python::YObject n();                                                         \
static PyObject *PYTHON_FUNCTION(n)(PyObject*,PyObject *pArgs)         \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (n()).IncRef();                                              \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}

#define DEFINE_PYTHON_METHOD_VIRTUAL(n)                                     \
static const int PYTHON_METHOD_TYPE(n)=METH_VARARGS;                        \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,PyObject *pArgs)     \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n(pArgs)).IncRef();         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
virtual python::YObject n(const python::YObject&)

#define REDEFINE_PYTHON_METHOD(n)                                           \
virtual python::YObject n(const python::YObject&)

#define DEFINE_PYTHON_METHOD_NOARGS(n)                                      \
static const int PYTHON_METHOD_TYPE(n)=METH_NOARGS;                         \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,PyObject *pArgs)     \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n()).IncRef();              \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject n()

#define DEFINE_PYTHON_METHOD_NOARGS_VIRTUAL(n)                              \
static const int PYTHON_METHOD_TYPE(n)=METH_NOARGS;                         \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,PyObject *pArgs)     \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n()).IncRef();              \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
virtual python::YObject n()

#define REDEFINE_PYTHON_METHOD_NOARGS(n)                                    \
virtual python::YObject n()

#define DEFINE_PYTHON_STRMETHOD(n)                                          \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf)                     \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n()).IncRef();              \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject n()

#define DEFINE_PYTHON_LENMETHOD(n)                                          \
static Py_ssize_t PYTHON_METHOD(n)(PyObject *pSelf)                    \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return GetInstanceFromPyObject(pSelf)->n();                         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        return 0;                                                           \
    }                                                                       \
}                                                                           \
int n()

#define DEFINE_PYTHON_COMPMETHOD(n)                                         \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,PyObject *pOther,int pType)  \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n(pOther,pType)).IncRef();  \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject n(const python::YObject &pOther,int pType)


#define DEFINE_PYTHON_HASHMETHOD(n)                                         \
static long PYTHON_METHOD(n)(PyObject *pSelf)                          \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return GetInstanceFromPyObject(pSelf)->n();                         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return -1;                                                          \
    }                                                                       \
}                                                                           \
long n()


#define DEFINE_PYTHON_INDEXMETHOD(n)                                        \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,Py_ssize_t pN)       \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n(pN)).IncRef();            \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject n(int pN)

#define DEFINE_PYTHON_GETATTRMETHOD(n)                                        \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,PyObject *pName)       \
{                                                                           \
    try                                                                     \
    {                                                                       \
        python::YObject lName(pName);                                       \
        if(!lName.IsString()) return nullptr;                                  \
        return (GetInstanceFromPyObject(pSelf)->n(lName.ToString())).IncRef();            \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject n(const std::string &pN)

#define DEFINE_PYTHON_BINARY_OPERATOR(n)                                    \
static PyObject *PYTHON_METHOD(n)(PyObject *p1,PyObject *p2)           \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (n(p1,p2)).IncRef();                                         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
static python::YObject n(const python::YObject &p1,const python::YObject &p2)

#define DEFINE_PYTHON_UNARY_OPERATOR(n)                                     \
static PyObject *PYTHON_METHOD(n)(PyObject *p1)                        \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (n(p1)).IncRef();                                            \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
static python::YObject n(const python::YObject &p1)

#define DEFINE_PYTHON_TERNARY_OPERATOR(n)                                   \
static PyObject *PYTHON_METHOD(n)(PyObject *p1,PyObject *p2,           \
                                                    PyObject *p3)           \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (n(p1,p2,p3)).IncRef();                                      \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
static python::YObject n(const python::YObject &p1,const python::YObject &p2,const python::YObject &p3)

#define DEFINE_PYTHON_CALLMETHOD(n)                                   \
static PyObject *PYTHON_METHOD(n)(PyObject *pSelf,PyObject *pArgs,           \
                                                    PyObject *pKw)           \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->n(pArgs,pKw)).IncRef();         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject n(const python::YObject &pArgs,const python::YObject &pKw)


#define DEFINE_CONSTRUCTOR(t)                                               \
static t *PythonConstructorWrapper(const python::YObject &pArgs)                    \
{                                                                           \
    return Construct(pArgs);                                                \
}                                                                           \
static t *Construct(const python::YObject &pArgs)

#define DEFINE_CONSTRUCTOR_NOARGS(t)                                        \
static t *PythonConstructorWrapper(const python::YObject &pArgs)                    \
{                                                                           \
    return Construct();                                                     \
}                                                                           \
static t *Construct()

#define DEFINE_DEFAULT_CONSTRUCTOR(t)                                       \
static t *PythonConstructorWrapper(const python::YObject &pArgs)                    \
{                                                                           \
    return new t;                                                           \
}

#define DEFINE_PYTHON_GET(n)                                                \
static PyObject *PYTHON_GET(n)(PyObject *pSelf,void*)                  \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->Get##n()).IncRef();         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject Get##n()

#define DEFINE_PYTHON_GETSET(n)                                             \
static PyObject *PYTHON_GET(n)(PyObject *pSelf,void*)                  \
{                                                                           \
    try                                                                     \
    {                                                                       \
        return (GetInstanceFromPyObject(pSelf)->Get##n()).IncRef();         \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return python::YObject();                                                   \
    }                                                                       \
}                                                                           \
python::YObject Get##n();                                                           \
static int PYTHON_SET(n)(PyObject *pSelf,PyObject *pValue,void*)       \
{                                                                           \
    try                                                                     \
    {                                                                       \
        (GetInstanceFromPyObject(pSelf)->Set##n(pValue)).IncRef();          \
        return 0;                                                           \
    }                                                                       \
    catch(std::exception &pX)                                                       \
    {                                                                       \
        PyErr_SetString(PyExc_RuntimeError,pX.what());                      \
        return -1;                                                          \
    }                                                                       \
}                                                                           \
python::YObject Set##n(const python::YObject&)

#define PYTHON_OP_ADD       1
#define PYTHON_OP_SUB       2
#define PYTHON_OP_MUL       3
#define PYTHON_OP_DIV       4
#define PYTHON_OP_NEG       5
#define PYTHON_OP_POW       6

/*namespace buola*/ }

#endif
